/**
  ******************************************************************************
  * @file    com.c
  * @author  Amaseing team
  * @version V1.0.0
  * @date    21-november-2013
  * @brief   Com
  *         
  ******************************************************************************  
  */ 
  
/* Private includes ----------------------------------------------------------*/ 
#include "com.h"

/* Private declarations ------------------------------------------------------*/
comHandler callBackCom;
struct comPacket comP;
uint8_t comReadPos = 0;

/* Private prototypes --------------------------------------------------------*/
/**
 * @brief Function initializes NVIC controller for USART interrupt(s)
 */
void usart_NVIC_Config(void);

/* Private defines -----------------------------------------------------------*/
/* Functions -----------------------------------------------------------------*/
void comInit(comHandler h)
{
	GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure; 
	
	callBackCom = h;
	
	// Clocks
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

	// Alternative pin configuration
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);

	// Pin config
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

	/*
		USARTx configured as follow:
			- BaudRate = 115200 baud  
			- 8 Bits
			- One Stop Bit
			- No parity
			- Hardware flow control disabled (RTS and CTS signals)
			- Receive and transmit    
	*/

  USART_InitStructure.USART_BaudRate = 115200;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_Init(USART2, &USART_InitStructure);
	
  // Enable the USART interrupts
  USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);

  USART_Cmd(USART2, ENABLE);
  usart_NVIC_Config();
}

int comWrite(uint32_t type, void* data, uint32_t len)
{
	struct comPacketHeader h = (struct comPacketHeader){type,len};
	int headerSize = sizeof(struct comPacketHeader);
	uint8_t* hPtr = (uint8_t*)&h;
	while(headerSize--) {
		USART_SendData(USART2, *hPtr++);
		while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
		
	}
	
	uint8_t *ptr = (uint8_t*)data;
	while(len--)
	{
		USART_SendData(USART2, *ptr++);
		while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
	}
	return 0;
}

void usart_NVIC_Config(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

  // Enable the USARTx Interrupt
  NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

void USART2_IRQHandler(void)
{
	static uint8_t *ptr;
	
	//Interrupt routine
	if(USART_GetITStatus(USART2, USART_IT_RXNE))
	{
		if(comReadPos < sizeof(struct comPacketHeader))
		{
			ptr = ((uint8_t*)(&(comP.header))) + comReadPos;
			*ptr = (uint8_t)(USART_ReceiveData(USART2) & 0x00FF);
			comReadPos++;
			USART_ClearITPendingBit(USART2, USART_IT_RXNE);
			return;
		}
		if(comReadPos >= sizeof(struct comPacketHeader))
		{
			ptr = (uint8_t*)(&(comP.header)) + comReadPos;
			*ptr = USART_ReceiveData(USART2);
			comReadPos++;
			
			if(comReadPos >= (COM_BUFFER_SIZE + sizeof(struct comPacketHeader)))
			{
				//Error: Message is to large to fit in the reserved memory
				comReadPos = 0;
				USART_ClearITPendingBit(USART2, USART_IT_RXNE);
				return;
			}
			
			if(comReadPos == (comP.header.size + sizeof(struct comPacketHeader)))
			{
				comReadPos = 0;
				
				//Full packet is received, but first clear the interrupt
				USART_ClearITPendingBit(USART2, USART_IT_RXNE);
				
				//Call the callback function
				callBackCom(comP.header.type,(void*)comP.data,comP.header.size);
				return;
			}
		}
		USART_ClearITPendingBit(USART2, USART_IT_RXNE);
	}
}

